//
// asm.c
// some assembler functions
//
// (c) 2008 why the lucky stiff, the freelance professor
//
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
// #include <assert.h>
#include "always_assert.h"
#include "potion.h"
#include "internal.h"
#include "opcodes.h"
#include "asm.h"

// TODO hsq PNAsm 用于三种目的（1. 为何不用 PNBytes 2. 构造类似的柔性(PN_OP)数组类型？ ）：
//    1. 语法解析时的字符串解析(potion_asm_write,potion_asm_clear@syntax.g)，
//    2. 编译生成字节码(potion_asm_op@compile.c)，
//    3. jit 生成汇编码(potion_asm_put@asm.h, potion_asm_write@vm-x86.c)
// 创建 PNAsm ，.vt=PN_TBYTES ，初始总内存占用为 ASM_UNIT 。
PNAsm *potion_asm_new(Potion *P) {
  int siz = ASM_UNIT - sizeof(PNAsm);
  PNAsm * volatile asmb = PN_FLEX_NEW(asmb, PN_TBYTES, PNAsm, siz);
  return asmb;
}

// 清空 PNAsm （初始状态）。
PNAsm *potion_asm_clear(Potion *P, PNAsm * volatile asmb) {
  asmb->len = 0;
  PN_MEMZERO_N(asmb->ptr, u8, asmb->siz);
  return asmb;
}

// 写入（追加）汇编指令， len 是字节数，可为 1 2 4 8 。按需扩容。
PNAsm *potion_asm_put(Potion *P, PNAsm * volatile asmb, PN val, size_t len) {
  u8 *ptr;
  PN_FLEX_NEEDS(len, asmb, PN_TBYTES, PNAsm, ASM_UNIT);
  ptr = asmb->ptr + asmb->len;

  if (len == sizeof(u8)) {
    assert(val <= UINT8_MAX || (long)val >= INT8_MIN);
    *ptr = (u8)val;
  } else if (len == 2) {
    assert(val <= UINT16_MAX || (long)val >= INT16_MIN);
    *((uint16_t *)ptr) = (uint16_t)val;
  } else if (len == sizeof(uint32_t)) {
    assert(val <= UINT32_MAX || (long)val >= INT32_MIN);
    *((int *)ptr) = (uint32_t)val;
  } else if (len == sizeof(PN)) {
    // assert(val <= ULONG_MAX);
    // assert(val <= UINT64_MAX);
    *((PN *)ptr) = val;
  }

  asmb->len += len;
  return asmb;
}

// 写入（追加）汇编指令：一个 PN_OP 结构，指令+双参 。按需扩容。
PNAsm *potion_asm_op(Potion *P, PNAsm * volatile asmb, int ins, int _a, int _b) {
  PN_OP *pos;
  PN_FLEX_NEEDS(sizeof(PN_OP), asmb, PN_TBYTES, PNAsm, ASM_UNIT);
  pos = (PN_OP *)(asmb->ptr + asmb->len);

  assert(ins <= OP_CODE_MAX);
  assert(_a <= OP_A_MAX);
  assert(_b <= OP_B_MAX);
  pos->code = ins;
  pos->a    = _a;
  pos->b    = _b;

  asmb->len += sizeof(PN_OP);
  return asmb;
}

// 写入（追加）汇编指令：一串字符串。按需扩容。
PNAsm *potion_asm_write(Potion *P, PNAsm * volatile asmb, char *str, size_t len) {
  char *ptr;
  PN_FLEX_NEEDS(len, asmb, PN_TBYTES, PNAsm, ASM_UNIT);
  ptr = (char *)asmb->ptr + asmb->len;
  PN_MEMCPY_N(ptr, str, char, len);
  asmb->len += len;
  return asmb;
}
